//# gridOnly
if(typeof(ksg) == "undefined") 
	ksg = {ui:{widgetMap:{}}};
//#

/**
* @namespace
* namespace - Contains all Kusog Grid related code items.
* @Depends ksg.baseWidget.js ksg.selectedRange.js
*/
ksg.ui.grid = {
	/**
	* @namespace
	*/
	columnTypes: {},
	columnDefinitions: { },
	templateHandlers: { },
	dataHandlerFactory: {
		basicArray: function(data, idFieldName) {
			return $.extend({},{
				getList: function(id, options, onSuccess) {
					onSuccess(data);
				},
				getTotalPossibleCount: function(options, onSuccess) {
					onSuccess(data.length);
				},
				getGeneralList: function(name, options) {
				},
				getIdFieldName: function() {
					return idFieldName;
				},
				shouldRequestChildListData: function() {
					return false;
				},
				hasValue: function(obj, fieldName) {
					return (fieldName in obj);
				},
				getValue: function(obj, fieldName) {
					return obj[fieldName];
				},
				setValue: function(obj, fieldName, val) {
					obj[fieldName] = val;
				}
			});
		}
	}
};


/**
* @class
* abstract class - Displays and manages a list of bizobjs in a grid formatted display, but it takes a child class to complete
* the functionality.
* The bizobj list can also be a BizObjTree structure, which will then allow the user to drill down into branches within the tree.
* @see ksg.ui.grid.DataGrid
* @meta-type abstract base class
* @importance high
*/
ksg.ui.grid.BaseGrid = {
	// default options
	options: {
		totalL1FieldName: "counts.totalL1",
		depthFieldName: "depth",
		hoverRowClass: "ui-state-highlight",
		selectedRowClass: "ui-state-active"
	},

	/**
	* The currently selected row's unique id value.
	* @type object
	*/
	selectedBizObjId: null,
   
	_create: function () { var options = this.options, self = this;
		this.id = this.element.attr('id');
		if(!(this.id))
			this.id = "";
		if(this._internalCreate) this._internalCreate();
		
		if(typeof(options.parentBizProc) == "string")
			options.parentBizProc = eval(options.parentBizProc + "BizProc");
		//ksg.ui.getTemplate(options.template, "", function(tmpl) {self._initGrid(tmpl.tmpl);} );
		this.templates.baseGrid(function(tmpl) {
			self._initGrid(tmpl);
		});
	},
	
	destroy: function() {
		if(this._internalDestroy) this._internalDestroy();
	},

	_initGrid: function(tmpl) {var $this = this.element, self = this, options = this.options;
		if(this._internalInitGrid) this._internalInitGrid(tmpl);
		
		var grid = this; //Used by grid tmpl to call methods
		$(tmpl).tmpl(this.options).appendTo($this);
		this._mergeDefaultColumnOptions();
		this._setupColHeaders();

		$this.find(".gcol").live({
			'keydown': function(event) {
				var $editElement = $(this).find('.ksg-grid-cellEditor');
				var keycode = event.keyCode;
				var $gcol = null;
				var index = $(this).parentsUntil("tr").index() +1;
				if(keycode == 40)//down arrow
					$gcol = $(this).parentsUntil("tbody").next().find("td:nth-child("+index+") > .gcol");					
				else if(keycode == 38) //up arrow
					$gcol = $(this).parentsUntil("tbody").prev().find("td:nth-child("+index+") > .gcol");
				else {
					var atBegining = true, atEnd = true;
					var isContentEditable = ($editElement.hasClass('ksg-grid-cellEditor') && $editElement.attr('contentEditable') == "true")
					if(isContentEditable) {
						var selInfo = $editElement.selectedRange('getRange');
						atBegining = selInfo.start == 0;
						atEnd = selInfo.end == selInfo.contentLength;
						//var selInfo = $editElement.getSelection();
						//atBegining = selInfo.start==0;
						//atEnd = selInfo.end == selInfo.length;
					}
					
					var moveLeftCell = (keycode == 37 && atBegining);
					var moveRightCell = (keycode == 39 && atEnd);
					
					if(moveLeftCell || moveRightCell) {
						var ctime = new Date().getTime();
						if(!(self.lastCurMoveTime && (ctime - self.lastCurMoveTime < 70))) {
							self.lastCurMoveTime = ctime;
							if(moveLeftCell) {
								var $prev = $(this).parentsUntil("tr").prev();
								if($prev.length == 0)
									$gcol = $(this).parentsUntil("tbody").last().prev().find("td:last > .gcol");
								else
									$gcol = $prev.find(".gcol");
							}
							else if(moveRightCell) {
								var $next = $(this).parentsUntil("tr").next();
								if($next.length == 0)
									$gcol = $(this).parentsUntil("tbody").last().next().find("td:first > .gcol");
								else
									$gcol = $next.find(".gcol");
							}
						}
					}
				}
							
				if($gcol != null) {
					self._setEditCell($gcol,keycode);
					return false;
				}
			},
			'focus': function(event) {
				if($(event.target).hasClass("ksg-grid-cellEditor") == false) {
					var $innerControl = $(this).find(".ksg-grid-cellEditor");
					if($innerControl.length > 0) {
						if($innerControl[0].isContentEditable) {
							$innerControl.selectedRange('setCarot','start');
						}
						self._setEditCell($(this));
					}
				}
			},
			'mousedown': function(event) {
				self._setEditCell($(this));
			}
		});
		
		$this.find(".ksg-grid-dataRow").live({
			'mouseover': function(event) {
				$(this).addClass(options.hoverRowClass);
			},
			'mouseout':function(event) {
				$(this).removeClass(options.hoverRowClass);
			}
		});
		
		var lsResize = function (event, ui) {
			self.resize();
		};
		
		$(window).resize(function() {
			self.resize();
		});
		
		$this.resizable({
			containment: $this.parent().parent(),
			handles: 'e',
			resize: lsResize,
			stop: lsResize
		});
		
		$this.find(".ksg-grid-rowArea").scroll(function (e) {
			$this.find(".ksg-grid-header").scrollLeft($(".ksg-grid-rowArea").scrollLeft());
		});
		
		$this.find(".ksg-grid-rowArea table").selectable({
			filter: 'td',
			selected: function (event, ui) {
				var $this = $(ui.selected);
				var sid = $this.parentsUntil('tbody').last().find('.ksg-id').val().toString();
				//var s = $this.find('.ui-selected');
				//s.find(".gcol").focus();
				//var sr = s.parent();
				//var sid = sr.find('.ksg-id').val().toString();//.replace(/-/g, '');
				self._selectBizObj(sid);
			}
		});
		$this.find(".treeBut").live("mousedown", function () {
			self._expandBranch($(this));
		});
		$this.find(".ksg-viewit-nav").live("mousedown", function () {
			$this.trigger("click");
		});
		
		if(self.options.parentIdWidget)
			$("#"+self.options.parentIdWidget).live("bizObjSelected", function(event, pid) {
				options.baseServiceOptions.pid = pid;
				self._resetGridData();
			});
		
		
		self._resetGridData();

		//# asp.net bizproc support
		if(typeof(bizProcManager) != 'undefined')
		bizProcManager.addAfterAjaxEventHandler(function (doc, eventInfo) {
			if (eventInfo.eventId.match(/update$/i) || eventInfo.eventId.match(/delete$/i)) {
				var x = 12;
				var sr = $this.find(".ksg-grid-rowArea .ui-selected").parent();
				var curDepth = Number(sr.find('#depth').val());
				var tr = self._findParent(sr);
				var rsid = sr.find('.ksg-id').val();
				var sid = tr.find('.ksg-id').val().toString().replace(/-/g, '');
				curDepth = Number(tr.find('#depth').val());
				
				//# data call
				//This code is designed to refresh the portion of the tree that the selected id is contained within					
				self.dataHandler.getList(sid, self.options, function (bizObjList) {
					self._removeChildren(tr);
					//ksg.ui.getTemplate(self.options.template, self._getTmplName("-data-row"), function(tmpl) {
					self.templates.dataRow(function(tmpl) {
						$(tmpl).tmpl({bizObjs:bizObjList, grid:self}, self.options).insertAfter(tr);
						tr.remove();
						setTimeout(function () { $(".ksg-id[value='" + rsid + "']").parent().parent().parent().find(".titleCol").parent().addClass("ui-selected"); 
							self._refreshTotal(true); }, 1);
						$this.trigger("tmplApplied");
					});
				});
				//#---
			}
		});
		//#---
	},
	
	getRowIdValue: function(bizObj) {
		return this._formatRowIdValue(this.dataHandler.getValue(bizObj,this._getIdFieldName()));
	},
	
	_formatRowIdValue:function(bizObjId) {
		return this.id + "_r_" + bizObjId.replace(/ /g, "^");
	},
	
	_selectBizObj: function(selectedId, fromInternalSelect, fromSetEditCell, fromRefresh) {
		var self = this, el = this.element, options = this.options, $idField = $(document.getElementById(self._formatRowIdValue(selectedId)));
		if(fromRefresh != true && self.selectedBizObjId == selectedId)
			return;
		self.selectedBizObjId = selectedId;
		if($idField.length == 0 && !(selectedId)) {
			el.trigger("bizObjSelected", selectedId);
			if(this._internalSelectBizObj) this._internalSelectBizObj(selectedId);
		}
		else
			$idField.each(function() {
				var $id = $(this);
				if($id.val() == selectedId || selectedId == null) {
					selectedId = $id.val();
					if(self.selectedRow)
						self.selectedRow.removeClass(options.selectedRowClass);
					self.selectedRow = $id.parentsUntil("tbody").last().addClass(options.selectedRowClass);
					//$id.parentsUntil("table").last().find("."+options.selectedRowClass).removeClass(options.selectedRowClass);
					//$id.parentsUntil("tbody:last").addClass(options.selectedRowClass);
					el.trigger("bizObjSelected", selectedId);
					if(fromSetEditCell != true)
						self._setEditCell($id.parentsUntil("tbody").last().find("td:first > .gcol"));
					if(fromInternalSelect != true && self._internalSelectBizObj) self._internalSelectBizObj(selectedId, fromRefresh);					
					return false;					
				}
			});
	},

	_setEditCell: function($gcol,keycode) {
		var inEdit = $gcol.find(".ksg-grid-cellInEdit");
		if(inEdit.length != 0)
			return;
			
		var $cell = $gcol.find(".ksg-grid-cellEditor");
		var cellTypeName = $cell.attr('cellType');
		var cellType = ksg.ui.grid.columnTypes[cellTypeName];
		if(cellType) {
			if(this._lastEditCell) {
				this._completeCellEdit(this._lastEditCell);
				this._lastEditCell.find(".ksg-grid-cellInEdit").removeClass("ksg-grid-cellInEdit");
			}
			this._lastEditCell = $gcol;
			if(cellType.edit)
				cellType.edit(this, $gcol, $cell, null, null);
				
			var $innerControl = $gcol.find(".ksg-grid-cellEditor");
			if($innerControl.length > 0) {
				$innerControl.addClass("ksg-grid-cellInEdit");
				if($innerControl.attr('contentEditable') == "true") {
					$innerControl.selectedRange('setCarot',keycode==37?'end':'start');
				}
				$innerControl.focus();
			}
		}
		this._selectBizObj($gcol.parent().parent().find(".ksg-id:input").val(),false, true);
	},
	
	_completeCellEdit: function($gcol) {
		var $cell = $gcol.find(".ksg-grid-cellEditor");
		var cellTypeName = $cell.attr('cellType');
		var cellType = ksg.ui.grid.columnTypes[cellTypeName];
		if(cellType && cellType.completeEdit)
				cellType.completeEdit(this, $gcol, $cell, null, null);
	},
	
	getRowChildState: function(rowIndex, bizObj, bizObjs) {		
		var options = this.options;
		var childState = 0; //0 = no children; 1=has children, but not in list; 2=has children, and present in list
		if (this.dataHandler.getValue(bizObj, options.totalL1FieldName) > 0)
			childState = 1;
			
		if(bizObjs.length > rowIndex+1 && this.dataHandler.getValue(bizObjs[rowIndex+1], options.depthFieldName) > this.dataHandler.getValue(bizObj, options.depthFieldName))
			childState = 2;

		return childState;
	},

	resize: function() {
		var el = this.element;
		el.find(".ksg-grid-header").width(el.width()); 
		el.find(".ksg-grid-rowArea").width(el.width());
		el.find(".ksg-grid-rowArea").height(el.height() - el.find(".ksg-grid-header").outerHeight(true) - el.find(".ksg-grid-footer").outerHeight(true));                
		this._refreshColumnSizes();
	},

	_mergeDefaultColumnOptions: function() {
		var columns = this.options.columns;
		if(columns)
			for(var i = 0; i < columns.length; i++) {				
				var defName = this.options.type + "-" + columns[i].id;
				var defCol = ksg.ui.grid.columnDefinitions[defName];
				if(defCol)
					columns[i] = $.extend({}, defCol, columns[i]);
			}
	},

	_getDataFieldId: function(col) {
		var id = col.dataField;
		if(!id || id == "")
			id = col.id;
		return id;
	},
	
	_hasIdField: function() {
		return ((this.idFieldName || this.options.columns["_id"] || ksg.ui.grid.columnDefinitions[this.options.type + "-_id"]) != null);
	},
	
	_getIdFieldName: function() {
		if(this.idFieldName)
			return this.idFieldName;

		this.idFieldName = null;
		if(this.options.columns["_id"])
			this.idFieldName = this.options.columns["_id"].dataField;				
		else if(this.options.type && ksg.ui.grid.columnDefinitions[this.options.type + "-_id"])
			this.idFieldName = ksg.ui.grid.columnDefinitions[this.options.type + "-_id"].dataField;

			if(this.idFieldName == null)
			this.idFieldName = this.dataHandler.getIdFieldName();
			
		return this.idFieldName;
	},
	
	_getTmplName: function(ending) {
		var options = this.options;
		var rowType = "";
		if(options.subType && options.subType != "")
			rowType = "-" + options.subType;
		return rowType + ending;
	},
		
	_setupColHeaders: function() {
		var $this = this.element, self = this, options = this.options;
		var $thead = $this.find(".ksg-grid-header table thead");		
		
		var sizeCol = function(col) {
			$this.find(".ksg-grid-rowArea ." + col.id).width($(col).outerWidth());
		};
			
		//ksg.ui.getTemplate(options.template, this._getTmplName("-header-row"), function(tmpl) {
		self.templates.header(function(tmpl) {
			var $cols = $(tmpl).tmpl(options).appendTo($thead);
			self.resize();
			$cols.find(".ghcol:not(.ksg-not-resizable)").resizable({ handles: 'e',
				resize: function (event, ui) {
					sizeCol(this);
				},
				stop: function (event, ui) {
					sizeCol(this);
				}
			});
		});
	},
	
	_refreshColumnSizes: function() {
		var $this = this.element;
		this.element.find(".ghcol").each(function() {
			$this.find(".ksg-grid-rowArea ." + this.id).width($(this).outerWidth());
		});
	},
		
	_resetGridData: function() {var $this = this.element, self = this, options = this.options;
		var $tb = $this.find(".ksg-grid-rowArea table tbody");
		$tb.children().remove();
		//# data call
		// This gets the initial list of top level parents to show after reseting the grid
		self.dataHandler.getList("", options, function (bizObjList) {
			//$this.data("initData", json);
			var bizObjs = bizObjList;
			var proc = function() {
				$this.trigger("tmplApplied");
				self._refreshTotal(true);
				self.resize();
				if(self._internalResetDataComplete) self._internlResetDataComplete();
				if(self.selectedBizObjId) {
					self._selectBizObj(self.selectedBizObjId, false, false, true);
				}
			};
			if(bizObjs && bizObjs.length > 0)
				//ksg.ui.getTemplate(options.template, self._getTmplName("-data-row"), function (tmpl) {
				self.templates.dataRow(function(tmpl) {
					$(tmpl).tmpl({bizObjs:bizObjs, grid:self}, options).appendTo($tb).find(".treeBut");
					proc();
				});
			else
				proc();
		});
		//# ---
	},
	
	_getCellTemplate: function(col, bizObj) {
		var isEditabled = this.options.editable;
		var colType= ksg.ui.grid.columnTypes[col.type];
		if(!colType)
			colType=ksg.ui.grid.columnTypes["text"];
		
		return colType.std(this,col,bizObj,isEditabled);
	},

	_refreshTotal: function(includeTotalRows) {var $this = this.element, options = this.options;
		$this.find(".gcol").attr("tabindex",0);
		$visibleRows = $this.find(".ksg-bizObjList-visibleRows");
		var visRowCount = $this.find(".ksg-grid-rowArea tr").length;
		$visibleRows.text(visRowCount);
		this._refreshColumnSizes();
		if (includeTotalRows) {
			var $totalRows = $this.find(".ksg-bizObjList-totalRows");
			//# data call
			//Gets the total number of rows available to be shown in the grid, including child nodes
			this.dataHandler.getTotalPossibleCount(options, function (count) {
				if(count)
					$totalRows.text(count);
				else
					$totalRows.text(visRowCount);
			});
			//# ---
		}
	},

	_removeChildren: function(cr) {
		var curDepth = Number(cr.find('#depth').val());
		var nr = cr.next();
		while (Number(nr.find('#depth').val()) > curDepth) {
			var o = nr;
			nr = nr.next();
			if(this.dataHandler.shouldRequestChildListData())
				o.remove();
			else {
				var southItems = o.find(".ui-icon-triangle-1-s");
				o.hide();
				southItems.removeClass("ui-icon-triangle-1-s").addClass("ui-icon-triangle-1-e");
				if(o.data("expanded") == true || southItems.length != 0)
					o.data("expanded", false);				
			}
		}
	},

	_findParent: function(cr) {
		var tr = cr;
		var curDepth = Number(cr.find('#depth').val());
		var pr = cr.prev();
		if (curDepth > 0)
			while (Number(pr.find('#depth').val()) != curDepth - 1) {
				pr = pr.prev();
				tr = pr;
			}
		return tr;
	},
		
	_expandBranch: function(el) {var $this = this.element, self = this, options = this.options;
		var sr = el.parentsUntil("tbody").last();
		var sid = sr.find('.ksg-id').val();
		if(sid)
			sid.toString().replace(/-/g, '');

		var curDepth = Number(sr.find('#depth').val());
		var ex = sr.data("expanded");
		if (typeof (ex) == 'undefined') {
			var nextSr = sr.next();
			var nextDepth = Number(nextSr.find('#depth').val());
			ex =(nextDepth > curDepth);
		}
		var numChildren = Number(sr.find('#numChildren').val());
		//if (numChildren > 0) {
			if (ex == true || ex == 'true') {
				el.removeClass("ui-icon-triangle-1-s").addClass("ui-icon-triangle-1-e");
				sr.data("expanded", false);
				this._removeChildren(sr);
				this._refreshTotal(false);
			}
			else {
				el.removeClass("ui-icon-triangle-1-e").addClass("ui-icon-triangle-1-s");
				sr.data("expanded", true);
				var nr = sr.next();
				if (nr.find('#depth').val() <= curDepth) {
					//# data call
					//Gets the child elements of the selected node to insert into the grid.
					self.dataHandler.getList(sid, options, function (bizObjList) {
						//ksg.ui.getTemplate(options.template, self._getTmplName("-data-row"), function(tmpl) {
						self.templates.dataRow(function(tmpl) {
							$(tmpl).tmpl({bizObjs:bizObjList, grid:self}, options).insertAfter(sr).find(".treeBut");
							self._refreshTotal(true);
							$this.trigger("tmplApplied");
						});
					});
					//# ---
				}
				else {
					while (Number(nr.find('#depth').val()) > curDepth) {
						if (Number(nr.find('#depth').val()) == curDepth + 1)
							nr.show();
						nr = nr.next();
					}
				}
			}
		//}            
	}
};

/**
* @augments ksg.ui.grid.BaseGrid
* @class
* Data Grid that uses the basic array data handler to manage its data.
* @meta-type jQuery widget
*/
ksg.ui.grid.DataGrid = $.extend({}, ksg.ui.grid.BaseGrid, /** @lends ksg.ui.grid.DataGrid# */{
	_internalCreate: function() {
		this.templates = ksg.ui.grid.templateHandlers.tmpl;
		this._setupGridDataHandler([]);
	},
	_internalDestroy: function() {
	},
	_internalInitGrid: function() {
	},
	_setupGridDataHandler: function(dataArray) {
		this.dataHandler = ksg.ui.grid.dataHandlerFactory.basicArray(dataArray);
	},
	_internalSelectBizObj: function(dataId) {
	},

	/**
	* Given an array of objects, will display them based on base grid configuration.
	*/
	displayData: function(dataArray) {
		this._setupGridDataHandler(dataArray);
		this._resetGridData();
	}
});

$.widget("ksg.dataGrid", ksg.ui.grid.DataGrid);
ksg.ui.widgetMap["ksg-dataGrid"] = function ($el, options) {
	$el.dataGrid(options); 
};



